﻿using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Collections.Specialized;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using System.Xml;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.WorkflowActions;
using Microsoft.Office.Workflow.Utility;
using System.IO;
using System.Data;
using Microsoft.VisualStudio.Tools.Applications;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Text;
using System.Net.Mail;

namespace SalesForecastStateWorkflow
{
    public sealed partial class Workflow1 : StateMachineWorkflowActivity
    {
        private string approverAccount = default(string);
        private string approverName = default(string);
        private string approverEmail = default(string);
        private string originatorAccount = default(string);
        private string originatorName = default(string);
        private string originatorEmail = default(string);
        private string instructions = default(string);
        private string comments = default(string);
        private string emailBody = default(string);
        private string emailSubject = default(string);
        private string emailTo = default(string);
        private string emailFrom = default(string);
        private StringDictionary mailHeaders = new StringDictionary();
        private DateTime taskDueBy = default(System.DateTime);
        private bool isApproved = false;
        private bool isRejected = false;
        private string historyDescription = default(System.String); 
        private Guid approverTaskId = default(System.Guid);
        private SPWorkflowTaskProperties approverTaskProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        private SPWorkflowTaskProperties approverAfterTaskProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        private SPWorkflowTaskProperties approverBeforeTaskProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        private Guid reviewTaskId = default(System.Guid);
        private SPWorkflowTaskProperties reviewTaskProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        private SPWorkflowTaskProperties reviewAfterTaskProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        private SPWorkflowTaskProperties reviewBeforeTaskProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        private SPWorkflowActivationProperties workflowProperties = new SPWorkflowActivationProperties();

        public string EmailBody
        {
            get
            {
                return emailBody;
            }
            set
            {
                emailBody = value;
            }
        }

        public string EmailSubject
        {
            get
            {
                return emailSubject;
            }
            set
            {
                emailSubject = value;
            }
        }

        public string EmailTo
        {
            get
            {
                return emailTo;
            }
            set
            {
                emailTo = value;
            }
        }

        public string EmailFrom
        {
            get
            {
                return emailFrom;
            }
            set
            {
                emailFrom = value;
            }
        }

        public StringDictionary MailHeaders
        {
            get
            {
                return mailHeaders;
            }
            set
            {
                mailHeaders = value;
            }
        }

        public DateTime TaskDueBy
        {
            get
            {
                return taskDueBy;
            }
            set
            {
                taskDueBy = value;
            }
        }

        public string HistoryDescription
        {
            get
            {
                return historyDescription;
            }
            set
            {
                historyDescription = value;
            }
        }

        public Guid ApproverTaskId
        {
            get
            {
                return approverTaskId;
            }
            set
            {
                approverTaskId = value;
            }
        }

        public SPWorkflowTaskProperties ApproverTaskProperties
        {
            get
            {
                return approverTaskProperties;
            }
            set
            {
                approverTaskProperties = value;
            }
        }

        public SPWorkflowTaskProperties ApproverAfterTaskProperties
        {
            get
            {
                return approverAfterTaskProperties;
            }
            set
            {
                approverAfterTaskProperties = value;
            }
        }

        public SPWorkflowTaskProperties ApproverBeforeTaskProperties
        {
            get
            {
                return approverBeforeTaskProperties;
            }
            set
            {
                approverBeforeTaskProperties = value;
            }
        }

        public Guid ReviewTaskId
        {
            get
            {
                return reviewTaskId;
            }
            set
            {
                reviewTaskId = value;
            }
        }

        public SPWorkflowTaskProperties ReviewTaskProperties
        {
            get
            {
                return reviewTaskProperties;
            }
            set
            {
                reviewTaskProperties = value;
            }
        }

        public SPWorkflowTaskProperties ReviewAfterTaskProperties
        {
            get
            {
                return reviewAfterTaskProperties;
            }
            set
            {
                reviewAfterTaskProperties = value;
            }
        }

        public SPWorkflowTaskProperties ReviewBeforeTaskProperties
        {
            get
            {
                return reviewBeforeTaskProperties;
            }
            set
            {
                reviewBeforeTaskProperties = value;
            }
        }

        public SPWorkflowActivationProperties WorkflowProperties
        {
            get
            {
                return workflowProperties;
            }
            set
            {
                workflowProperties = value;
            }
        }

        public Workflow1()
        {
            InitializeComponent();
        }


        private void onWorkflowActivated1_Invoked(object sender, ExternalDataEventArgs e)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(WorkflowInstantiationData));
            XmlTextReader reader = new XmlTextReader(new System.IO.StringReader(this.workflowProperties.InitiationData));
            WorkflowInstantiationData instantiationData = null;
            try
            {
                instantiationData = (WorkflowInstantiationData)serializer.Deserialize(reader);
            }
            catch (Exception err)
            {
                // Add an error logging module and capture the activating user and document
                //string a = err.Message;
            }

            this.instructions = instantiationData.comments;
            SPUser originatingUser = this.workflowProperties.OriginatorUser;
            // The following lines translate the system reference for the administrator user to 
            // instead reference the administrator directly.
            if (string.Compare(originatingUser.LoginName, "SHAREPOINT\\system", true, CultureInfo.InvariantCulture) == 0)
            {
                originatingUser = this.workflowProperties.Web.SiteUsers["litwareinc\\administrator"];
            }
            ServerDocument serverDocument = new ServerDocument(this.workflowProperties.Item.File.OpenBinary(), ".xlsx");
            CachedDataHostItem hostItem = serverDocument.CachedData.HostItems["SalesForecastWorkbook.ThisWorkbook"];
            CachedDataItem salesManagerIdData = hostItem.CachedData["ManagerEmployeeID"];
            serializer = new XmlSerializer(Type.GetType(salesManagerIdData.DataType));
            int salesManagerId = (int)serializer.Deserialize(new StringReader(salesManagerIdData.Xml));
            AdventureWorksVSTO advwrksDC = new AdventureWorksVSTO(Properties.Settings.Default.AdventureWorksConnectionString);
            advwrksDC.ObjectTrackingEnabled = false;
            var salesManager = from employee in advwrksDC.HumanResources_Employee
                               where employee.EmployeeID == salesManagerId
                               select employee;
            SPUser approvingUser = this.workflowProperties.Web.SiteUsers[salesManager.First().LoginID];
            this.originatorAccount = originatingUser.LoginName;
            this.approverAccount = approvingUser.LoginName;
            this.originatorEmail = originatingUser.LoginName.Substring(originatingUser.LoginName.IndexOf("\\") + 1) + "@LitwareInc.com";
            this.approverEmail = approvingUser.LoginName.Substring(approvingUser.LoginName.IndexOf("\\") + 1) + "@Litwareinc.com";
            this.originatorName = originatingUser.Name;
            this.approverName = approvingUser.Name;
            this.EmailTo = this.approverEmail;
            this.emailFrom = this.originatorEmail;
        }

        private void CreateApproverTask(object sender, EventArgs e)
        {
            this.approverTaskId = Guid.NewGuid();
            this.approverTaskProperties.Title = "Please approve this document";
            this.approverTaskProperties.AssignedTo = this.approverAccount;
            this.approverTaskProperties.Description = this.instructions;
            this.approverTaskProperties.TaskType = 0;
            this.taskDueBy = DateTime.Today.AddDays(5);
            this.approverTaskProperties.DueDate = this.taskDueBy;
            this.approverTaskProperties.SendEmailNotification = false;
            this.approverTaskProperties.ExtendedProperties["isApproved"] = "false";
            this.approverTaskProperties.ExtendedProperties["isRejected"] = "false";
            this.approverTaskProperties.ExtendedProperties["comments"] = "";
            this.approverTaskProperties.ExtendedProperties["instructions"] = this.instructions;
        }

        private void setApprovedHistoryDescription_ExecuteCode(object sender, EventArgs e)
        {
            string status = "approved";
            this.historyDescription =
                string.Format(
                    "Document '{0}' {1} by: {2}, submitted by: {3}",
                    this.workflowProperties.Item.Name,
                    status,
                    this.approverName,
                    this.originatorName);
            SPUser approvingUser = this.workflowProperties.Web.SiteUsers[this.approverAccount];
            this.logToHistoryListActivity_UserId = approvingUser.ID;
            return;
        }

        private void onTaskChanged1_Invoked(object sender, ExternalDataEventArgs e)
        {
            this.isApproved = bool.Parse(this.approverAfterTaskProperties.ExtendedProperties["isApproved"].ToString());
            this.isRejected = bool.Parse(this.approverAfterTaskProperties.ExtendedProperties["isRejected"].ToString());
            // apparently the tasks are run under the System.Administrator account... could be the workflow account
            // the result is the same, you can't use the current identity to tell you who triggered the workflow.
            //string testName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
            string comment = this.approverAfterTaskProperties.ExtendedProperties["instructions"].ToString();
            if (string.IsNullOrEmpty(comment) || comment == this.instructions)
                comment = this.approverAfterTaskProperties.ExtendedProperties["comments"].ToString();
            this.comments =
                string.Format(
                    "\r\n{0} Review Comments:\r\n{1}",
                    this.approverName,
                    comment);
            this.instructions =
                string.Format(
                    "{0}\r\n----------------------------------\r\n{1}",
                    this.comments,
                    this.instructions);

            return;
        }

        private void sendApprovalRequestedEmail_ExecuteCode(object sender, EventArgs e)
        {
            // Define the email message
            MailMessage requestAppMessage = new MailMessage();
            // Define the subject
            requestAppMessage.Subject =
                string.Format(
                    "{0} has requested approval for the document '{1}'",
                    this.originatorName,
                    this.workflowProperties.Item.Name);

            // Define the body
            requestAppMessage.Body =
                string.Format(
                    "<html><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>" +
                    "		<style>" +
                    "			table.mail" +
                    "			{{border-style:none;border-collapse:collapse;font:8pt Tahoma;width:100%}}" +
                    "			td.header" +
                    "			{{background:#F8F8F9;border:1px solid #E8EAEC;padding:12pt 10px 4pt 10px}}" +
                    "			td.body" +
                    "			{{padding:12pt 10px 24pt 10px}}" +
                    "			td.footer" +
                    "			{{border-width:1px;border-style:solid none none none;border-color:#9CA3AD;padding:4pt 10px 4pt 10px}}" +
                    "			a" +
                    "			{{text-decoration:none}}" +
                    "			div.title" +
                    "			{{font:16pt Verdana}}" +
                    "			div.headertext" +
                    "			{{margin:5px 0px 0px 0px}}" +
                    "			div.error" +
                    "			{{font-weight:bold}}" +
                    "			div.comment" +
                    "			{{color:#9CA3AD}}" +
                    "			span.wfname" +
                    "			{{font:bold italic}}" +
                    "		</style>" +
                    "	</head>" +
                    "	<body>" +
                    "		<table cellpadding='2' cellspacing='0' class='mail' dir='none'><tbody><tr class='header'>" +
                    "					<td class='header'>" +
                    "						<div class='error'>{0}</div>" +
                    "							<div class='error'>Due by {1}</div>" +
                    "					</td></tr><tr class='body'>" +
                    "					<td class='body' valign='top'>" +
                    "						{3}'s Comments:<div class='error'> {2}</div>" +
                    "					</td></tr><tr class='footer'><td class='footer'>" +
                    "To complete this task open this message in it's own window and view the custom sales report display. <br/>" +
                    "						</td></tr></tbody>" +
                    "		</table>" +
                    "	</body>" +
                    "</html>",
                    requestAppMessage.Subject,
                    this.taskDueBy.ToShortDateString(),
                    this.instructions,
                    this.originatorName);

            // Get the cached data items we need in order to run the SQL Query
            // to build one of the attachments
            ServerDocument serverDocument = new ServerDocument(this.workflowProperties.Item.File.OpenBinary(), ".xlsx");
            CachedDataHostItem hostItem = serverDocument.CachedData.HostItems["SalesForecastWorkbook.ThisWorkbook"];
            CachedDataItem intData = hostItem.CachedData["SalesEmployeeID"];

            // the serializer is type based so group data based on type info.
            XmlSerializer serializer = new XmlSerializer(Type.GetType(intData.DataType));
            int salesEmployeeID = (int)serializer.Deserialize(new StringReader(intData.Xml));
            intData = hostItem.CachedData["ForecastID"];
            int forecastID = (int)serializer.Deserialize(new StringReader(intData.Xml));
            intData = hostItem.CachedData["SalesContactID"];
            int salesContactID = (int)serializer.Deserialize(new StringReader(intData.Xml));
            intData = hostItem.CachedData["TerritoryID"];
            int territoryID = (int)serializer.Deserialize(new StringReader(intData.Xml));
            CachedDataItem forecastDateData = hostItem.CachedData["ForecastDate"];
            serializer = new XmlSerializer(Type.GetType(forecastDateData.DataType));
            DateTime forecastDate = (DateTime)serializer.Deserialize(new StringReader(forecastDateData.Xml));

            requestAppMessage.To.Add(approverEmail);
            requestAppMessage.From = new System.Net.Mail.MailAddress(originatorEmail);

            // Create an attachment
            MemoryStream attachMe = new MemoryStream();
            XmlWriter xmlAttach = XmlWriter.Create(attachMe);
            xmlAttach.WriteStartDocument();
            xmlAttach.WriteStartElement("CompanyData");
            // Retrieve data from AdventureWorks
            AdventureWorksVSTO advwrksDC = new AdventureWorksVSTO(Properties.Settings.Default.AdventureWorksConnectionString);
            advwrksDC.ObjectTrackingEnabled = false;
            PopulateGeneralInfo(xmlAttach, salesContactID, territoryID, forecastDate, advwrksDC);
            PopulateSalesData(xmlAttach, forecastID, salesEmployeeID, forecastDate, advwrksDC);
            xmlAttach.WriteEndElement();
            xmlAttach.WriteEndDocument();
            xmlAttach.Flush();

            // Add attachments
            attachMe.Position = 0;
            requestAppMessage.Attachments.Add(new Attachment(attachMe, "LitwareForeCastData.xml", "text/xml"));

            requestAppMessage.IsBodyHtml = true;
            SmtpClient smtp = new SmtpClient("localhost");
            smtp.Send(requestAppMessage);
            return;
        }

        private void PopulateGeneralInfo(XmlWriter XmlAttach, int salesContactID, int territoryID, DateTime forecastDate, AdventureWorksVSTO advwrksDC)
        {
            // Populate the XML structure
            XmlAttach.WriteStartElement("GeneralInfo");
            //              <CompanyName>company name</CompanyName>
            XmlAttach.WriteElementString("CompanyName", "Litware Inc.");
            //              <TerritoryName>territory name</TerritoryName>
            var territory = from terrtbl in advwrksDC.Sales_SalesTerritory
                            where terrtbl.TerritoryID == territoryID
                            select terrtbl;
            XmlAttach.WriteElementString("TerritoryName", territory.First().Name);
            ////              <TerritoryID>territory id</TerritoryID>
            XmlAttach.WriteElementString("TerritoryID", territoryID.ToString());
            ////              <Region>region name</Region>
            XmlAttach.WriteElementString("Region", territory.First().CountryRegionCode.ToString());
            ////              <SalesManager>sales manager name</SalesManager>
            XmlAttach.WriteElementString("SalesManager", approverName);
            ////              <SalesPerson>sales person name</SalesPerson>
            var salesperson = from contactTbl in advwrksDC.Person_Contact
                              where contactTbl.ContactID == salesContactID
                              select contactTbl;
            XmlAttach.WriteElementString("SalesPerson", salesperson.First().FirstName + " " + salesperson.First().LastName);
            //              <SalesPersonID>sales person id</SalesPersonID>
            XmlAttach.WriteElementString("SalesPersonID", salesContactID.ToString());
            //              <ReportDate>report date</ReportDate>
            XmlAttach.WriteElementString("ReportDate", forecastDate.ToString("s"));
            //              <SpreadSheetUrl>spreadsheet uri</SpreadSheetUrl>
            Uri spreadSheetUri = new Uri(string.Format("{0}/{1}",
                                    this.workflowProperties.Web.Url,
                                    this.workflowProperties.Item.Url));
            XmlAttach.WriteElementString("SpreadSheetUrl", spreadSheetUri.ToString());
            ////              <ReportUrl>report url</ReportUrl> - since the report name will match the .xlsx name only in a different list...
            string docUri = spreadSheetUri.ToString().ToLower();
            docUri = docUri.Replace(".xlsx", ".docx");
            docUri = docUri.Replace("/sales forecasts/", "/documents/");
            XmlAttach.WriteElementString("ReportUrl", docUri);
            ////              <Comments>comments</Comments>
            XmlAttach.WriteElementString("Comments", instructions);
            //          </GeneralInfo>
            XmlAttach.WriteEndElement();
        }

        private void PopulateSalesData(XmlWriter XmlAttach, int forecastID, int salesEmployeeID, DateTime forecastDate, AdventureWorksVSTO advwrksDC)
        {
            XmlAttach.WriteStartElement("Sales");

            // Write out the customer data
            GenerateCustomerXml(XmlAttach, forecastID, salesEmployeeID, forecastDate, advwrksDC);

            //          </Sales>
            XmlAttach.WriteEndElement();
        }

        private static void GenerateCustomerXml(XmlWriter XmlAttach, int forecastID, int salesEmployeeID, DateTime forecastDate, AdventureWorksVSTO advwrksDC)
        {
            var salesForecastQuery = from forecastestTbl in advwrksDC.Sales_ForecastEstimates
                                     where forecastestTbl.ForeCastID == forecastID
                                     select forecastestTbl;
            int lastCustomer = 0;
            foreach (var forecast in salesForecastQuery)
            {
                int currentCustomer = forecast.CompanyID;
                if (lastCustomer != currentCustomer)
                {
                    if (lastCustomer != 0)
                    {
                        //  </Customer>
                        XmlAttach.WriteEndElement();
                    }

                    //  <Customer>
                    XmlAttach.WriteStartElement("Customer");
                    //      <Name>customer name</Name>
                    var customer = from customerTbl in advwrksDC.Sales_Customer
                                   where customerTbl.CustomerID == currentCustomer
                                   select customerTbl;

                    XmlAttach.WriteElementString("Name", customer.First().CustomerName);
                    //      <CustomerID>customer id</CustomerID>
                    XmlAttach.WriteElementString("CustomerID", currentCustomer.ToString());

                    GenerateQuarterXml(XmlAttach, forecastID, salesEmployeeID, currentCustomer, forecastDate, advwrksDC);

                    lastCustomer = currentCustomer;
                }
            }
            //   </Customer>
            XmlAttach.WriteEndElement();

            return;
        }

        private static void GenerateQuarterXml(XmlWriter writerXml, int forecastID, int salesEmployeeID, int customerID, DateTime forecastDate, AdventureWorksVSTO advwrksDC)
        {
            int qtr = 0;
            string year = "2008";
            ForecastData data;
            Dictionary<int, ForecastData> quarterlySales = new Dictionary<int, ForecastData>(4);
            // unlike forecasts, we only need to compute the start year for the fiscal
            // information and then build the 4 quarters
            qtr = GetFYKey(forecastDate.Month, forecastDate.Year, out year);
            for (int i = 1; i < 5; i++)
            {
                data = new ForecastData();
                data.Sales = 0;
                data.Probability = 0;
                data.Quarter = i;
                if (i <= qtr)
                {
                    data.FiscalYear = year;
                }
                else
                {
                    data.FiscalYear = (Convert.ToInt16(year) - 1).ToString();
                }
                quarterlySales.Add(i, data);
            }

            //Need to ensure we get 4 quarters... may only get three - in which case need a 4th...
            var qtrSales = advwrksDC.UspGetSalesDataByFiscalQuarters(salesEmployeeID, customerID, forecastDate);
            foreach (UspGetSalesDataByFiscalQuartersResult actSales in qtrSales)
            {
                // Populate the appropriate quarters.  Note that in a demo scenario this can return more
                // then 4 quarters worth of data, which is why we have to map the quarters to the correct data.
                qtr = actSales.FiscalQuarter.Value;
                if (quarterlySales[qtr].FiscalYear == actSales.FiscalYear.ToString())
                {
                    data = quarterlySales[qtr];
                    data.Sales = actSales.ActualSales.Value;
                    quarterlySales[qtr] = data;
                    //QuarterlySales[qtr].Sales = actSales.ActualSales.Value;
                }
            }
            for (qtr = 1; qtr < 5; qtr++)
            {
                //      <FiscalYear>
                writerXml.WriteStartElement("FiscalYear");
                //          <Name>fiscal year name</Name>
                writerXml.WriteElementString("Name", quarterlySales[qtr].FiscalYear);
                //          <Quarters>
                writerXml.WriteStartElement("Quarters");

                //  <Quarter>
                writerXml.WriteStartElement("Quarter");
                //      <Name>quarter name</Name>
                writerXml.WriteElementString("Name", quarterlySales[qtr].Quarter.ToString());
                //      <ActualSales>0.00</ActualSales>
                writerXml.WriteElementString("ActualSales", quarterlySales[qtr].Sales.ToString("C"));
                //      <RawForecast>0.00</RawForecast>
                writerXml.WriteElementString("RawForecast", Decimal.Zero.ToString("C"));
                //      <Probability>.50</Probability>
                writerXml.WriteElementString("Probability", Decimal.Zero.ToString("P"));
                //      <AdjustedForecast>0.00</AdjustedForecast>
                writerXml.WriteElementString("AdjustedForecast", Decimal.Zero.ToString("C"));
                //      <Variance>0.00</Variance>
                writerXml.WriteElementString("Variance", Decimal.Zero.ToString("C"));
                //  </Quarter>
                writerXml.WriteEndElement();

                // </Quarters>
                writerXml.WriteEndElement();
                // </FiscalYear>
                writerXml.WriteEndElement();
            }

            Dictionary<int, ForecastData> quarterlyForecasts = new Dictionary<int, ForecastData>(4);
            var salesforecast = from forecastEstTbl in advwrksDC.Sales_ForecastEstimates
                                where forecastEstTbl.CompanyID == customerID && forecastEstTbl.ForeCastID == forecastID
                                select forecastEstTbl;
            foreach (var salesforecastrow in salesforecast)
            {
                qtr = GetFYKey(salesforecastrow.Month, salesforecastrow.Year, out year);
                if (quarterlyForecasts.ContainsKey(qtr))
                {
                    // If the quarter has been started continue to add the 
                    //values (reduce the total percentage by 3 when used.)
                    data = quarterlyForecasts[qtr];
                    data.Probability += salesforecastrow.Confidence;
                    data.Sales += salesforecastrow.SalesForecast;
                    quarterlyForecasts[qtr] = data;
                }
                else
                {
                    // First entry for a new forecast - create a new entry.
                    data = new ForecastData();
                    data.FiscalYear = year;
                    data.Quarter = qtr;
                    data.Probability = salesforecastrow.Confidence;
                    data.Sales = salesforecastrow.SalesForecast;
                    quarterlyForecasts.Add(qtr, data);
                }
            }
            for (qtr = 1; qtr < 5; qtr++)
            {
                // Now get the forecast for the matching quarters...
                //      <FiscalYear>
                writerXml.WriteStartElement("FiscalYear");
                //          <Name>fiscal year name</Name>
                writerXml.WriteElementString("Name", quarterlyForecasts[qtr].FiscalYear);
                //          <Quarters>
                writerXml.WriteStartElement("Quarters");

                // A quarter's worth of data...
                //  <Quarter>
                writerXml.WriteStartElement("Quarter");
                //      <Name>quarter name</Name>
                writerXml.WriteElementString("Name", quarterlyForecasts[qtr].Quarter.ToString());
                //      <ActualSales>0.00</ActualSales>
                writerXml.WriteElementString("ActualSales", Decimal.Zero.ToString("C"));
                //      <RawForecast>0.00</RawForecast>
                writerXml.WriteElementString("RawForecast", quarterlyForecasts[qtr].Sales.ToString("C"));
                //      <Probability>.50</Probability>
                writerXml.WriteElementString("Probability", (quarterlyForecasts[qtr].Probability / 3).ToString("P"));
                //      <AdjustedForecast>0.00</AdjustedForecast>
                writerXml.WriteElementString("AdjustedForecast", (quarterlyForecasts[qtr].Sales * ((quarterlyForecasts[qtr].Probability / 3) / 100)).ToString("C"));
                //      <Variance>0.00</Variance>
                //if (actualSales > Decimal.Zero)
                //{
                //    variance = actualSales - rawForecast;
                //}
                writerXml.WriteElementString("Variance", Decimal.Zero.ToString("C"));
                //  </Quarter>
                writerXml.WriteEndElement();

                // </Quarters>
                writerXml.WriteEndElement();
                // </FiscalYear>
                writerXml.WriteEndElement();
            }
            return;
        }

        private static int GetFYKey(int month, int year, out string fyyear)
        {
            int qtr = 1;
            fyyear = "2009";
            switch (month)
            {
                case 1:
                case 2:
                case 3:
                    fyyear = (year).ToString();
                    qtr = 3;
                    break;
                case 4:
                case 5:
                case 6:
                    fyyear = (year).ToString();
                    qtr = 4;
                    break;
                case 7:
                case 9:
                case 8:
                    fyyear = (year + 1).ToString();
                    qtr = 1;
                    break;
                case 10:
                case 11:
                case 12:
                    fyyear = (year + 1).ToString();
                    qtr = 2;
                    break;
                default:
                    break;
            }
            return qtr;
        }

        private void DocumentIsApproved(object sender, ConditionalEventArgs e)
        {
            e.Result = this.isApproved;

            return;
        }

        private void DocumentIsRejected(object sender, ConditionalEventArgs e)
        {
            e.Result = this.isRejected;

            return;
        }

        private void setRejectedHistoryDescription_ExecuteCode(object sender, EventArgs e)
        {
            string status = "rejected";
            this.historyDescription =
                string.Format(
                    "Document '{0}' {1} by: {2}, submitted by: {3}",
                    this.workflowProperties.Item.Name,
                    status,
                    this.approverName,
                    this.originatorName);
            SPUser approvingUser = this.workflowProperties.Web.SiteUsers["litwareinc\\sjiang"];
            this.logToHistoryListActivity_UserId = approvingUser.ID;
            return;
        }

        private void setRequestChangesHistoryDescription_ExecuteCode(object sender, EventArgs e)
        {
            this.historyDescription =
            string.Format(
                "Changes requested for document '{0}' by: {1}, submitted by: {2}",
            this.workflowProperties.Item.Name,
            this.approverName,
            this.originatorName);
            SPUser approvingUser = this.workflowProperties.Web.SiteUsers["litwareinc\\sjiang"];
            this.logToHistoryListActivity_UserId = approvingUser.ID;
            return;
        }

        #region "Standard Emails"
        private void sendApprovedEmail_MethodInvoking(object sender, EventArgs e)
        {
            this.emailSubject =
                string.Format(
                    "The document '{0}' has been approved",
                    this.workflowProperties.Item.DisplayName);
            this.EmailTo = this.originatorEmail;
            this.emailFrom = this.approverEmail;
            this.emailBody =
                string.Format(
                    "<html>" +
                    "    <head>" +
                    "        <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>" +
                    "        <style>" +
                    "            table.mail" +
                    "            {{border-style:none;" +
                    "            border-collapse:collapse;" +
                    "            font:8pt Tahoma;" +
                    "            width:100%}}" +
                    "            td.header" +
                    "            {{background:#F8F8F9;" +
                    "            border:1px solid #E8EAEC;" +
                    "            padding:12pt 10px 4pt 10px}}" +
                    "            td.body" +
                    "            {{padding:12pt 10px 24pt 10px}}" +
                    "            td.footer" +
                    "            {{border-width:1px;" +
                    "            border-style:solid none none none;" +
                    "            border-color:#9CA3AD;" +
                    "            padding:4pt 10px 4pt 10px}}" +
                    "            a" +
                    "            {{text-decoration:none}}" +
                    "            div.title" +
                    "            {{font:16pt Verdana}}" +
                    "            div.headertext" +
                    "            {{margin:5px 0px 0px 0px}}" +
                    "            div.error" +
                    "            {{font-weight:bold}}" +
                    "            div.comment" +
                    "            {{color:#9CA3AD}}" +
                    "            span.wfname" +
                    "            {{font:bold italic}}" +
                    "        </style>" +
                    "    </head>" +
                    "    <body>" +
                    "        <table cellpadding='2' cellspacing='0' class='mail' dir='none'>" +
                    "            <tbody>" +
                    "                <tr class='header'>" +
                    "                    <td class='header'>" +
                    "	                    <div class='title'>{0}</div>" +
                    "                    </td>" +
                    "                </tr>" +
                    "                <tr class='body'>" +
                    "                    <td class='body' valign='top'>" +
                    "	                    <div>{1}</div>" +
                    "                    </td>" +
                    "                </tr>" +
                    "                <tr class='footer'>" +
                    "                    <td class='footer'>" +
                    "	                    <div class='comment'>" +
                    "		                    For more information about this task:" +
                    "		                    <br/>" +
                    "		                    <ol>" +
                    "			                    <li>" +
                    "				                    Review <a href='{2}' target='_blank'>" +
                    "					                    {3}" +
                    "				                    </a>." +
                    "			                    </li>" +
                    "			                    <li>" +
                    "				                    <a href='{4}' target='_blank'>Review the workflow</a>." +
                    "			                    </li>" +
                    "		                    </ol>" +
                    "	                    </div>" +
                    "                    </td>" +
                    "                </tr>" +
                    "            </tbody>" +
                    "        </table>" +
                    "    </body>" +
                    "</html>",  //Properties.Resources.WorkflowCompleteMessageTemplate,
                    string.Format(
                        "The document '{0}' has been approved by {1}.", //Properties.Resources.MSG_DOCUMENT_APPROVED_TITLE,
                        this.workflowProperties.Item.DisplayName,
                        this.approverName),
                    this.comments,
                    string.Format(
                        "{0}/{1}",
                        this.workflowProperties.Web.Url,
                        this.workflowProperties.Item.Url),
                    this.workflowProperties.Item.Name,
                    string.Format(
                        "{0}/_layouts/WrkStat.aspx?List={1}&WorkflowInstanceID={2}",
                        this.workflowProperties.Web.Url,
                        this.workflowProperties.ListId.ToString("B"),
                        this.workflowProperties.WorkflowId.ToString("B")));

            return;
        }

        private void sendRejectedEmail_MethodInvoking(object sender, EventArgs e)
        {
            this.emailSubject =
                string.Format(
                    "The document '{0}' has been rejected",
                    this.workflowProperties.Item.DisplayName);
            this.EmailTo = this.originatorEmail;
            this.emailFrom = this.approverEmail;
            this.emailBody =
                string.Format(
                    "<html>" +
                    "    <head>" +
                    "        <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>" +
                    "        <style>" +
                    "            table.mail" +
                    "            {{border-style:none;" +
                    "            border-collapse:collapse;" +
                    "            font:8pt Tahoma;" +
                    "            width:100%}}" +
                    "            td.header" +
                    "            {{background:#F8F8F9;" +
                    "            border:1px solid #E8EAEC;" +
                    "            padding:12pt 10px 4pt 10px}}" +
                    "            td.body" +
                    "            {{padding:12pt 10px 24pt 10px}}" +
                    "            td.footer" +
                    "            {{border-width:1px;" +
                    "            border-style:solid none none none;" +
                    "            border-color:#9CA3AD;" +
                    "            padding:4pt 10px 4pt 10px}}" +
                    "            a" +
                    "            {{text-decoration:none}}" +
                    "            div.title" +
                    "            {{font:16pt Verdana}}" +
                    "            div.headertext" +
                    "            {{margin:5px 0px 0px 0px}}" +
                    "            div.error" +
                    "            {{font-weight:bold}}" +
                    "            div.comment" +
                    "            {{color:#9CA3AD}}" +
                    "            span.wfname" +
                    "            {{font:bold italic}}" +
                    "        </style>" +
                    "    </head>" +
                    "    <body>" +
                    "        <table cellpadding='2' cellspacing='0' class='mail' dir='none'>" +
                    "            <tbody>" +
                    "                <tr class='header'>" +
                    "                    <td class='header'>" +
                    "	                    <div class='title'>{0}</div>" +
                    "                    </td>" +
                    "                </tr>" +
                    "                <tr class='body'>" +
                    "                    <td class='body' valign='top'>" +
                    "	                    <div>{1}</div>" +
                    "                    </td>" +
                    "                </tr>" +
                    "                <tr class='footer'>" +
                    "                    <td class='footer'>" +
                    "	                    <div class='comment'>" +
                    "		                    For more information about this task:" +
                    "		                    <br/>" +
                    "		                    <ol>" +
                    "			                    <li>" +
                    "				                    Review <a href='{2}' target='_blank'>" +
                    "					                    {3}" +
                    "				                    </a>." +
                    "			                    </li>" +
                    "			                    <li>" +
                    "				                    <a href='{4}' target='_blank'>Review the workflow</a>." +
                    "			                    </li>" +
                    "		                    </ol>" +
                    "	                    </div>" +
                    "                    </td>" +
                    "                </tr>" +
                    "            </tbody>" +
                    "        </table>" +
                    "    </body>" +
                    "</html>",  //Properties.Resources.WorkflowCompleteMessageTemplate,
                    string.Format(
                        "The document '{0}' has been rejected by {1}.", //Properties.Resources.MSG_DOCUMENT_REJECTED_TITLE,
                        this.workflowProperties.Item.DisplayName,
                        this.approverName),
                    this.comments,
                    string.Format(
                        "{0}/{1}",
                        this.workflowProperties.Web.Url,
                        this.workflowProperties.Item.Url),
                    this.workflowProperties.Item.Name,
                    string.Format(
                        "{0}/_layouts/WrkStat.aspx?List={1}&WorkflowInstanceID={2}",
                        this.workflowProperties.Web.Url,
                        this.workflowProperties.ListId.ToString("B"),
                        this.workflowProperties.WorkflowId.ToString("B")));

            return;
        }

        private void sendChangesRequestedEmail_MethodInvoking(object sender, EventArgs e)
        {
            this.emailSubject =
                string.Format(
                    "Changes have been requested on the document '{0}'",
                    this.workflowProperties.Item.DisplayName);
            this.EmailTo = this.originatorEmail;
            this.emailFrom = this.approverEmail;
            this.emailBody =
                string.Format(
                    "<html>" +
                    "	<head>" +
                    "		<meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>" +
                    "		<style>" +
                    "			table.mail" +
                    "			{{border-style:none;" +
                    "			border-collapse:collapse;" +
                    "			font:8pt Tahoma;" +
                    "			width:100%}}" +
                    "			td.header" +
                    "			{{background:#F8F8F9;" +
                    "			border:1px solid #E8EAEC;" +
                    "			padding:12pt 10px 4pt 10px}}" +
                    "			td.body" +
                    "			{{padding:12pt 10px 24pt 10px}}" +
                    "			td.footer" +
                    "			{{border-width:1px;" +
                    "			border-style:solid none none none;" +
                    "			border-color:#9CA3AD;" +
                    "			padding:4pt 10px 4pt 10px}}" +
                    "			a" +
                    "			{{text-decoration:none}}" +
                    "			div.title" +
                    "			{{font:16pt Verdana}}" +
                    "			div.headertext" +
                    "			{{margin:5px 0px 0px 0px}}" +
                    "			div.error" +
                    "			{{font-weight:bold}}" +
                    "			div.comment" +
                    "			{{color:#9CA3AD}}" +
                    "			span.wfname" +
                    "			{{font:bold italic}}" +
                    "		</style>" +
                    "	</head>" +
                    "	<body>" +
                    "		<table cellpadding='2' cellspacing='0' class='mail' dir='none'>" +
                    "			<tbody>" +
                    "				<tr class='header'>" +
                    "					<td class='header'>" +
                    "						<div class='title'>{0}</div>" +
                    "						<br/>" +
                    "							<div class='error'>Due by {1}</div>" +
                    "					</td>" +
                    "				</tr>" +
                    "				<tr class='body'>" +
                    "					<td class='body' valign='top'>" +
                    "						<div>{2}</div>" +
                    "					</td>" +
                    "				</tr>" +
                    "				<tr class='footer'>" +
                    "					<td class='footer'>" +
                    "						<div class='comment'>" +
                    "							To complete this task:" +
                    "							<br/>" +
                    "							<ol>" +
                    "								<li>" +
                    "									Review <a href='{3}' target='_blank'>" +
                    "										{4}" +
                    "									</a>." +
                    "								</li>" +
                    "								<li>Perform the specific activities required for this task.</li>" +
                    "								<li>" +
                    "									<a href='{5}' target='_blank'>Edit this task</a> to resubmit the document for approval." +
                    "								</li>" +
                    "							</ol>" +
                    "						</div>" +
                    "					</td>" +
                    "				</tr>" +
                    "			</tbody>" +
                    "		</table>" +
                    "	</body>" +
                    "</html>",  //Properties.Resources.ChangesRequestedMessageTemplate,
                    string.Format(
                        "Changes have been requested on the document '{0}' by {1}.", //Properties.Resources.MSG_DOCUMENT_CHANGESREQUESTED_TITLE,
                        this.workflowProperties.Item.DisplayName,
                        this.approverName),
                    this.taskDueBy.ToShortDateString(),
                    this.comments,
                    string.Format(
                        "{0}/{1}",
                        this.workflowProperties.Web.Url,
                        this.workflowProperties.Item.Url),
                    this.workflowProperties.Item.Name,
                    string.Format(
                        "{0}/_layouts/WrkStat.aspx?List={1}&WorkflowInstanceID={2}",
                        this.workflowProperties.Web.Url,
                        this.workflowProperties.ListId.ToString("B"),
                        this.workflowProperties.WorkflowId.ToString("B")));

            return;
        }
        #endregion

        private void ReviewTask_MethodInvoking(object sender, EventArgs e)
        {
            this.reviewTaskId = Guid.NewGuid();
            this.reviewTaskProperties.Title = "Your manager has requested changes to your document prior to approval. Please make the appropriate changes.";
            this.reviewTaskProperties.AssignedTo = this.originatorAccount;
            this.reviewTaskProperties.Description = this.instructions;
            this.reviewTaskProperties.TaskType = 1;
            this.taskDueBy = DateTime.Today.AddDays(5);
            this.reviewTaskProperties.DueDate = this.taskDueBy;
            this.reviewTaskProperties.SendEmailNotification = false;
            this.reviewTaskProperties.ExtendedProperties["isApproved"] = "false";
            this.reviewTaskProperties.ExtendedProperties["isRejected"] = "false";
            this.reviewTaskProperties.ExtendedProperties["comments"] = "";
            this.reviewTaskProperties.ExtendedProperties["instructions"] = this.instructions;
        }

        public static DependencyProperty logToHistoryListActivity_UserIdProperty = DependencyProperty.Register("logToHistoryListActivity_UserId", typeof(System.Int32), typeof(SalesForecastStateWorkflow.Workflow1));

        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [BrowsableAttribute(true)]
        [CategoryAttribute("Misc")]
        public Int32 logToHistoryListActivity_UserId
        {
            get
            {
                return ((int)(base.GetValue(SalesForecastStateWorkflow.Workflow1.logToHistoryListActivity_UserIdProperty)));
            }
            set
            {
                base.SetValue(SalesForecastStateWorkflow.Workflow1.logToHistoryListActivity_UserIdProperty, value);
            }
        }

    }

    internal struct ForecastData
    {
        public decimal Sales { get; set; }
        public int Probability { get; set; }
        public string FiscalYear { get; set; }
        public int Quarter { get; set; }

    }

}
